package me.zhengjie.tool;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 业务基础工具类
 *
 * @author FW
 */
public class BaseUtil implements Serializable {

    private static final long serialVersionUID = -2709967437776985406L;

    /**比较字符串和给定对象是否相等，通常用来比较常量和map中获取的数据*/
    public static boolean stringCompareTo(String str,Object obj){
        // 常量不会为null，所以直接false
        if (obj == null){
            return false;
        }
        // 不是String直接false
        if (!(obj instanceof String)){
            return false;
        }
        return str.equals(obj);
    }

    /**
     * 比较两个实体属性值，返回一个boolean,true则表时两个对象中的属性值无差异
     *
     * @param oldObject 进行属性比较的对象1
     * @param newObject 进行属性比较的对象2
     * @return 属性差异比较结果boolean
     */
    public static boolean compareObject(Object oldObject, Object newObject) {
        Map<String, Map<String, Object>> resultMap = compareFields(oldObject, newObject);

        if (resultMap.size() > 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 比较两个实体属性值，返回一个map以有差异的属性名为key，value为一个Map分别存oldObject,newObject此属性名的值
     *
     * @param oldObject 进行属性比较的对象1
     * @param newObject 进行属性比较的对象2
     * @return 属性差异比较结果map
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, Map<String, Object>> compareFields(Object oldObject, Object newObject) {
        Map<String, Map<String, Object>> map = null;

        try {
            /**
             * 只有两个对象都是同一类型的才有可比性
             */
            if (oldObject.getClass() == newObject.getClass()) {
                map = new HashMap<>();

                Class clazz = oldObject.getClass();
                //获取object的所有属性
                PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();

                for (PropertyDescriptor pd : pds) {
                    //遍历获取属性名
                    String name = pd.getName();

                    //获取属性的get方法
                    Method readMethod = pd.getReadMethod();

                    // 在oldObject上调用get方法等同于获得oldObject的属性值
                    Object oldValue = readMethod.invoke(oldObject);
                    // 在newObject上调用get方法等同于获得newObject的属性值
                    Object newValue = readMethod.invoke(newObject);

                    if (oldValue instanceof List) {
                        continue;
                    }

                    if (newValue instanceof List) {
                        continue;
                    }

                    if (oldValue instanceof Timestamp) {
                        oldValue = new Date(((Timestamp) oldValue).getTime());
                    }

                    if (newValue instanceof Timestamp) {
                        newValue = new Date(((Timestamp) newValue).getTime());
                    }

                    if (oldValue == null && newValue == null) {
                        continue;
                    } else if (oldValue == null && newValue != null) {
                        Map<String, Object> valueMap = new HashMap<>();
                        valueMap.put("oldValue", oldValue);
                        valueMap.put("newValue", newValue);

                        map.put(name, valueMap);

                        continue;
                    }

                    if (!oldValue.equals(newValue)) {// 比较这两个值是否相等,不等就可以放入map了
                        Map<String, Object> valueMap = new HashMap<>();
                        valueMap.put("oldValue", oldValue);
                        valueMap.put("newValue", newValue);

                        map.put(name, valueMap);
                    }
                }
            }
        } catch (Exception e) {
            LogUtil.error(e);
        }

        return map;
    }

    /**
     * 将domain转换成map
     *
     * @param domain
     * @return
     * @throws Exception
     */
    public static Map<String, Object> domainToMap(Object domain) throws Exception {
        Map<String, Object> map = new HashMap<>();
        Class cla = domain.getClass();
        Field[] fields = cla.getDeclaredFields();
        String fieldName;
        Method method;
        for (Field field : fields) {
            fieldName = field.getName();
            try {
                method = cla.getDeclaredMethod("get" + fieldName.substring(0, 1).toUpperCase() +
                        fieldName.substring(1, fieldName.length()));
            } catch (NoSuchMethodException e) {
                continue;
            }
            map.put(fieldName.toLowerCase(), method.invoke(domain));
        }
        return map;
    }

    /**
     * 检查传入对象的说明是否为NULL，为null则抛出异常
     *
     * @param msg 这个传入对象的名字
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:23:27
     * @version 1.0
     * @see
     */
    public static void checkMsg(String msg) {
        if (ValidateUtil.isEmpty(msg)) {
            throw new IllegalArgumentException("没有获取到需要检查对象的名称！");
        }
    }

    /**
     * 判断传入的Object是否为null，如果为null则抛出异常msg
     *
     * @param object 进行ValidateUtil.isEmpty判断的object
     * @param msg    抛出的异常错误信息
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月6日 下午2:40:56
     * @version 1.0
     * @see
     */
    public static void checkNull(Object object, String msg) {
        checkMsg(msg);
        if (ValidateUtil.isEmpty(object)) {
            throw new IllegalArgumentException("没有获取到【" + msg + "】");
        }
    }

    /**
     * 判断传入的Object是否为null，如果为null则抛出异常msg
     *
     * @param c   进行ValidateUtil.isEmpty判断的collection
     * @param msg 抛出的异常错误信息
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月6日 下午2:40:56
     * @version 1.0
     * @see
     */
    public static void checkNull(Collection c, String msg) {
        checkMsg(msg);
        if (ValidateUtil.isEmpty(c)) {
            throw new IllegalArgumentException("没有获取到【" + msg + "】");
        }
    }

    /**
     * 判断传入的Object是否为null，如果为null则抛出异常msg
     *
     * @param s   进行ValidateUtil.isEmpty判断的string
     * @param msg 抛出的异常错误信息
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月6日 下午2:40:56
     * @version 1.0
     * @see
     */
    public static void checkNull(String s, String msg) {
        checkMsg(msg);
        if (ValidateUtil.isEmpty(s)) {
            throw new IllegalArgumentException("没有获取到【" + msg + "】");
        }
    }

    /**
     * 检查数值是否为NULL，为null则抛出异常
     *
     * @param i   传入的需要检查的数值
     * @param msg 这个传入数值的名字
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:23:27
     * @version 1.0
     * @see
     */
    public static void checkNull(Integer i, String msg) {
        checkMsg(msg);
        if (ValidateUtil.isEmpty(i)) {
            throw new IllegalArgumentException("没有获取到【" + msg + "】");
        }
    }

    /**
     * 检查数值是否为NULL，为null则抛出异常
     *
     * @param d   传入的需要检查的数值
     * @param msg 这个传入数值的名字
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:23:27
     * @version 1.0
     * @see
     */
    public static void checkNull(Double d, String msg) {
        checkMsg(msg);
        if (ValidateUtil.isEmpty(d)) {
            throw new IllegalArgumentException("没有获取到【" + msg + "】");
        }
    }


    /**
     * 检查数值是否小于0, 小于0则抛出异常
     *
     * @param i   传入的需要检查的数值
     * @param msg 这个传入数值的名字
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:28:59
     * @version 1.0
     * @see
     */
    public static void checkIsPositiveNumber(Integer i, String msg) throws Exception {
        checkNull(i, msg);
        if (0.00 > i.doubleValue()) {
            throw new IllegalArgumentException("【" + msg + "】不能为负数");
        }
    }

    /**
     * 检查数值是否小于0, 小于0则抛出异常
     *
     * @param d   传入的需要检查的数值
     * @param msg 这个传入数值的名字
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:28:59
     * @version 1.0
     * @see
     */
    public static void checkIsPositiveNumber(Double d, String msg) throws Exception {
        checkNull(d, msg);
        if (0.00 > d.doubleValue()) {
            throw new IllegalArgumentException("【" + msg + "】不能为负数");
        }
    }

    /**
     * 检查数值边界，不能小于等于多少，不能大于等于多少
     *
     * @param num    数值
     * @param bottom 下边界
     * @param top    上边界
     * @param name   数值名称
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:50:49
     * @version 1.0
     * @see
     */
    public static void checkRange(Integer num, Integer bottom, Integer top, String name){
        checkNull(num, "需要判定范围的数值");
        checkNull(bottom, "下边界");
        checkNull(top, "上边界");
        if (num.doubleValue() >= bottom.doubleValue() && num.doubleValue() <= top.doubleValue()) {
            return;
        }
        if (num.doubleValue() >= top.doubleValue() && num.doubleValue() <= bottom.doubleValue()) {
            return;
        }
        throw new IllegalArgumentException(name + "【" + num.toString() + "】没有在 " + bottom.toString() + " 与 " + top.toString() + " 之间");
    }

    /**
     * 检查数值边界，不能小于等于多少，不能大于等于多少
     *
     * @param num    数值
     * @param bottom 下边界
     * @param top    上边界
     * @param name   数值名称
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月9日 下午8:50:49
     * @version 1.0
     * @see
     */
    public static void checkRange(Double num, Double bottom, Double top, String name) {
        checkNull(num, "需要判定范围的数值");
        checkNull(bottom, "下边界");
        checkNull(top, "上边界");
        if (num.doubleValue() >= bottom.doubleValue() && num.doubleValue() <= top.doubleValue()) {
            return;
        }
        if (num.doubleValue() >= top.doubleValue() && num.doubleValue() <= bottom.doubleValue()) {
            return;
        }
        throw new IllegalArgumentException(name + "【" + num.toString() + "】没有在 " + bottom.toString() + " 与 " + top.toString() + " 之间");
    }

    /**
     * 左补参数
     *
     * @param str
     * @param size    补充到多少位数
     * @param padChar 补充参数
     * @return
     */
    public static String leftPad(String str, int size, char padChar) {
        if (str == null)
            str = "";
        int pads = size - str.length();
        if (pads <= 0) {
            return str;
        }
        if (pads > 8192) {
            return leftPad(str, size, String.valueOf(padChar));
        } else {
            return repeat(padChar, pads).concat(str);
        }
    }

    public static String repeat(char ch, int repeat) {
        char[] buf = new char[repeat];
        for (int i = repeat - 1; i >= 0; i--) {
            buf[i] = ch;
        }
        return new String(buf);
    }

    /**
     * @param str
     * @param size
     * @param padStr
     * @return
     */
    public static String leftPad(String str, int size, String padStr) {
        if (str == null) {
            str = "";
        }
        if (ValidateUtil.isEmpty(padStr)) {
            padStr = " ";
        }
        int padLen = padStr.length();
        int strLen = str.length();
        int pads = size - strLen;
        if (pads <= 0) {
            return str;
        }
        if (padLen == 1 && pads <= 8192) {
            return leftPad(str, size, padStr.charAt(0));
        }
        if (pads == padLen) {
            return padStr.concat(str);
        }
        if (pads < padLen) {
            return padStr.substring(0, pads).concat(str);
        }
        char[] padding = new char[pads];
        char[] padChars = padStr.toCharArray();
        for (int i = 0; i < pads; i++) {
            padding[i] = padChars[i % padLen];
        }
        return (new String(padding)).concat(str);
    }

    /**
     * 验证座机号码
     */
    public static boolean isFixdPhone(String mobilePhone) {
        String regx = "([0-9]{3,4}-)?[0-9]{7,8}";
        Pattern p = Pattern.compile(regx);
        Matcher m = p.matcher(mobilePhone);

        return m.matches();
    }

    /**
     * 验证手机号码
     */
//    public static boolean isTelePhone(String telePhone) {
//        String regx = "^((13[0-9])|(15[^4,\\D])|(18[0-9]))\\d{8}$";
//        Pattern p = Pattern.compile(regx);
//        Matcher m = p.matcher(telePhone);
//        return m.matches();
//    }

    /**
     * 功能：判断字符串是否为数字
     *
     * @param str
     * @return boolean
     */
    public static boolean isNumeric(String str) {
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        return isNum.matches();
    }




}
